#include <sstream>
#include <QMessageBox>
#include <sys/socket.h>
#include <netinet/tcp.h>

#include "mainwindow.h"
#include "ui_mainwindow.h"

#define THRESHOLD 100000


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , camera("/dev/video0", 640, 480, 0)
{
    this->setWindowFlags(Qt::FramelessWindowHint);
    ui->setupUi(this);

    connect(ui->le_username, SIGNAL(clicked()), SLOT(username_Clicked()));
    connect(ui->le_password, SIGNAL(clicked()), SLOT(pw_Clicked()));
    ui->le_username->setPlaceholderText("User Name");
    connect(&adc_timer, SIGNAL(timeout()), this, SLOT(update_R()));
    connect(&cap_timer, SIGNAL(timeout()), this, SLOT(update_pic()));
    connect(&transfer_timer, SIGNAL(timeout()), this, SLOT(data_transfer_slot()));
    is_move = 0;
    history_lists = 0;
    setup_customplot(ui->customPlot);
    usr_or_pw = 1;
    serverConnected = false;
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::timer_task()
{
    /// update R
    int R = data.R;
    if(R == -1)
        ui->lb_R->setText("R: Error! ADC open failed!");
    else ui->lb_R->setText(QString("R: %1 Ohm").arg(R));
    if(R>9000)
        ui->lb_R_warn->setText("warn: R too high!");
    else if(R<1000)
        ui->lb_R_warn->setText("warn: R too low!");
    else ui->lb_R_warn->setText("warn: Normal...");

    //key的单位是秒
        double key = QDateTime::currentDateTime().toMSecsSinceEpoch()/1000.0;
        qsrand(QTime::currentTime().msec() + QTime::currentTime().second() * 10000);

        ui->customPlot->graph(0)->addData(key, R);//添加数据1到曲线1
        //删除8秒之前的数据。这里的8要和下面设置横坐标宽度的8配合起来
        //才能起到想要的效果，可以调整这两个值，观察显示的效果。
        ui->customPlot->graph(0)->removeDataBefore(key-8);

      //自动设定graph(1)曲线y轴的范围，如果不设定，有可能看不到图像
//也可以用ui->customPlot->yAxis->setRange(up,low)手动设定y轴范围

        ui->customPlot->graph(0)->rescaleValueAxis();

        //这里的8，是指横坐标时间宽度为8秒，如果想要横坐标显示更多的时间
        //就把8调整为比较大到值，比如要显示60秒，那就改成60。
        //这时removeDataBefore(key-8)中的8也要改成60，否则曲线显示不完整。
        ui->customPlot->xAxis->setRange(key+0.25, 8, Qt::AlignRight);//设定x轴的范围
        ui->customPlot->replot();

//    if(history_lists > 5)
//    {
//        ui->history_value_list->takeItem(1);
//        ui->history_value_list->takeItem(1);
//    }
//    else
//        history_lists++;
//     ui->history_value_list->addItem(QDateTime::currentDateTime().toString());
//    ui->history_value_list->addItem(QString::fromStdString("R: "+ss.str()+" Ohm"));
}

void MainWindow::update_pic()
{
    data.img = imgbuffer_now = camera.GetBuffer();
    ui->lb_pic->setPixmap(QPixmap::fromImage(imgbuffer_now.scaled(ui->lb_pic->size(), Qt::KeepAspectRatio)));
    if(imgbuffer_now.save("./pic/img"+QDateTime::currentDateTime().toString("yyyy/MM/dd-hh:mm:ss")+".jpg", "JPG", 100))
        qDebug("Picture save failed!");
}

void MainWindow::on_pb_exit_clicked()
{
    if (!(QMessageBox::information(this,tr("Exit App"),tr("Do you really want to Quit?"),tr("Yes"),tr("No"))))
    {
        QApplication::exit();
    }
}

void MainWindow::on_sb_ADC_Freq_valueChanged()
{
   adc_timer.setInterval((int)(ui->sb_ADC_Freq->value() * 1000));
}

void MainWindow::update_R()
{
    data.R = ad.adc_read();
    ui->lb_R->setText(QString("R: %1 Ohm").arg(data.R));
    timer_task();
}

void MainWindow::data_transfer_slot()
{
    QImage img;
    if(imgbuffer_past.isNull() == false && imgbuffer_now.isNull() == false)
    {
        is_move = movementDetection(imgbuffer_past, imgbuffer_now);

    //qDebug("%d \n", (is_move));
    }
    if(is_move > THRESHOLD)
    {
        if(history_lists > 5)
        {
            ui->history_value_list->takeItem(1);
            ui->history_value_list->takeItem(1);
        }
        else
            history_lists++;
        ui->history_value_list->addItem(QDateTime::currentDateTime().toString());
        ui->history_value_list->addItem("Movement Detected!");
        img = imgbuffer_now;
    }
    imgbuffer_past = imgbuffer_now.copy();
    /// upload data
    if(serverConnected)
    {
        outBlock.resize(0);
        data.timestamp = QDateTime::currentDateTime();
        QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
        sendOut.setVersion(QDataStream::Qt_4_6);
        sendOut << qint32(0x7FFFFFFF) << qint32(0) ///head
                << qint32(0x7FFFFFFF) << qint32(0)
                << qint32(0x7FFFFFFF) << qint32(0)
                << qint32(0x7FFFFFFF) << qint32(0) ///
                << qint32(0) //size
                << qint32(1) //datatype
                << Transfer(QDateTime::currentDateTime(), img, data.R);
        sendOut.device()->seek(sizeof(qint32)*8);
        sendOut<<qint32(outBlock.size());
        if(client.write(outBlock) != outBlock.size())
            qDebug() << "Connection closed unexpectedly!";
    }
}

void MainWindow::setup_customplot(QCustomPlot *customPlot)
{
    //#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0)
     //QMessageBox::critical(this, "", "You're using Qt < 4.7, the realtime data demo needs functions that are available with Qt 4.7 to work properly");
   //#endif
     //demoName = "Real Time Data Demo";

     // include this section to fully disable antialiasing for higher performance:
     /*
     customPlot->setNotAntialiasedElements(QCP::aeAll);
     QFont font;
     font.setStyleStrategy(QFont::NoAntialias);
     customPlot->xAxis->setTickLabelFont(font);
     customPlot->yAxis->setTickLabelFont(font);
     customPlot->legend->setFont(font);
     */
     customPlot->addGraph(); // blue line
     customPlot->graph(0)->setPen(QPen(Qt::blue));
     customPlot->graph(0)->setName("temp");
     //customPlot->graph(0)->setBrush(QBrush(QColor(240, 255, 200)));
     //customPlot->graph(0)->setAntialiasedFill(false);
     //customPlot->graph(0)->setChannelFillGraph(customPlot->graph(1));


     customPlot->xAxis->setTickLabelType(QCPAxis::ltDateTime);
     customPlot->xAxis->setDateTimeFormat("hh:mm:ss");
     customPlot->xAxis->setAutoTickStep(false);
     customPlot->xAxis->setTickStep(2);
     customPlot->axisRect()->setupFullAxesBox();

     // make left and bottom axes transfer their ranges to right and top axes:
     //connect(customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->xAxis2, SLOT(setRange(QCPRange)));
     //connect(customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->yAxis2, SLOT(setRange(QCPRange)));

     // setup a timer that repeatedly calls MainWindow::realtimeDataSlot:
     customPlot->legend->setVisible(false);
}


void MainWindow::on_pb_login_clicked()
{
    if(!serverConnected)
    {
        client.connectToHost(ui->le_addr_2->text(),ui->le_port_2->text().toInt());
        if(client.waitForConnected(5000))
        {
            qDebug()<<"Connect to "<<ui->le_addr_2->text()<<":"<<ui->le_port_2->text()<<" successful.";
            serverConnected = true;
            connect(&client,SIGNAL(disconnected()),this,SLOT(client_disconnected()));
            if(client.socketDescriptor() == -1)
            {
                qDebug("fail to get socketDescriptor");
            }
            else
            {
                qDebug("socketDescriptor %d", client.socketDescriptor());
            }

            //开启保活
            int enable = 1;
            if(setsockopt(client.socketDescriptor(), SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)) != 0)
            {
                qDebug("fail to enable SO_KEEPALIVE");
            }
            //失连时间>0
            int lost_time = 1;
            if(setsockopt(client.socketDescriptor(), SOL_TCP, TCP_KEEPIDLE, &lost_time, sizeof(lost_time)) != 0)
            {
                qDebug("fail to enable TCP_KEEPIDLE");
            }
            //重连时间>0
            int retry_time = 1;
            if(setsockopt(client.socketDescriptor(), SOL_TCP, TCP_KEEPINTVL, &retry_time, sizeof(retry_time)) != 0)
            {
                qDebug("fail to enable TCP_KEEPINTVL");
            }
            //重连次数>0
            int retry_num = 3;
            if(setsockopt(client.socketDescriptor(), SOL_TCP, TCP_KEEPCNT, &retry_num, sizeof(retry_num)) != 0)
            {
                qDebug("fail to enable TCP_KEEPCNT");
            }
        }
        else
        {
            QMessageBox::warning(this, tr("Login Failed"), tr("Connect to server failed!"));
            return;
        }
    }

    outBlock.resize(0);
    QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
    sendOut.setVersion(QDataStream::Qt_4_6);
    sendOut << qint32(0x7FFFFFFF) << qint32(0) ///head
            << qint32(0x7FFFFFFF) << qint32(0)
            << qint32(0x7FFFFFFF) << qint32(0)
            << qint32(0x7FFFFFFF) << qint32(0) ///
            << qint32(0) //size
            << qint32(2) //datatype
            << ui->le_username->text() << ui->le_password->text();
    sendOut.device()->seek(sizeof(qint32)*8);
    sendOut<<qint32(outBlock.size());
    if(client.write(outBlock) != outBlock.size())
        qDebug() << "Connection closed unexpectedly!";

    if(!client.waitForReadyRead(3000))
        qDebug() << "Server reponse timeout!";

    QByteArray inblock = client.readAll();
    QDataStream in(inblock);
    in.setVersion(QDataStream::Qt_4_6);

    qDebug() << "received data size: " << inblock.size();

    qint32 packSize, datatype;

    for(int i = 0; i < 4; ++i)
    {
        qint32 m,n;
        in >> m >> n;
        if(m != 0x7FFFFFFF || n != 0)
            qDebug("Head error!");
    }
    in >> packSize >> datatype;

    qDebug() << "packSize:" << packSize << ", datatype:" << datatype;

    if(datatype != 2)
    {
        QMessageBox::warning(this,tr("Auth error!"), tr("Server response error!"));
        return;
    }

    bool authresult;

    in >> authresult;

    if(authresult)
    {
        ui->frame->close();
        if(camera.OpenDevice())
            cap_timer.start(50);
        else qDebug("Open camera failed!");
        transfer_timer.start(500);
        adc_timer.start((int)(ui->sb_ADC_Freq->value() * 1000));
    }
    else
        QMessageBox::warning(this,tr("Login Failed"),tr("Username or password error!"),tr("Try again"));
}

void MainWindow::pw_Clicked()
{
    usr_or_pw = 0;
}

void MainWindow::username_Clicked() {
    //在处理lineedit clicked函数里我们将lineedit背景色变蓝色
    //ui->le_username->setStyleSheet("background-color:blue");
    usr_or_pw = 1;
}

void MainWindow::on_kb_a_clicked()
{
    if(usr_or_pw == 1)
        ui->le_username->insert("A");
    else if(usr_or_pw == 0)
        ui->le_password->insert("A");
}

void MainWindow::on_kb_b_clicked()
{
    if(usr_or_pw == 1)
        ui->le_username->insert("B");
    else if(usr_or_pw == 0)
        ui->le_password->insert("B");
}

void MainWindow::on_kb_c_clicked()
{
    if(usr_or_pw == 1)
        ui->le_username->insert("C");
    else if(usr_or_pw == 0)
        ui->le_password->insert("C");
}



void MainWindow::on_kb_d_clicked()
{
    if(usr_or_pw == 1)
        ui->le_username->insert("D");
    else if(usr_or_pw == 0)
        ui->le_password->insert("D");
}

void MainWindow::on_kb_e_clicked()
{
    if(usr_or_pw == 1)
        ui->le_username->insert("E");
    else if(usr_or_pw == 0)
        ui->le_password->insert("E");
}

void MainWindow::on_kb_f_clicked()
{
    if(usr_or_pw == 1)
        ui->le_username->insert("F");
    else if(usr_or_pw == 0)
        ui->le_password->insert("F");
}



void MainWindow::on_kb_g_clicked()
{
    if(usr_or_pw == 1)
        ui->le_username->insert("G");
    else if(usr_or_pw == 0)
        ui->le_password->insert("G");
}

void MainWindow::on_kb_h_clicked()
{
    if(usr_or_pw == 1)
        ui->le_username->insert("H");
    else if(usr_or_pw == 0)
        ui->le_password->insert("H");
}



void MainWindow::on_kb_i_clicked()
{
    if(usr_or_pw == 1)
        ui->le_username->insert("I");
    else if(usr_or_pw == 0)
        ui->le_password->insert("I");
}



void MainWindow::on_kb_j_clicked()
{
    if(usr_or_pw == 1)
        ui->le_username->insert("J");
    else if(usr_or_pw == 0)
        ui->le_password->insert("J");
}

void MainWindow::on_kb_k_clicked()
{
    if(usr_or_pw == 1)
        ui->le_username->insert("K");
    else if(usr_or_pw == 0)
        ui->le_password->insert("K");
}


void MainWindow::on_kb_l_clicked()
{
    if(usr_or_pw == 1)
        ui->le_username->insert("L");
    else if(usr_or_pw == 0)
        ui->le_password->insert("L");
}

void MainWindow::on_kb_m_clicked()
{
    if(usr_or_pw == 1)
        ui->le_username->insert("M");
    else if(usr_or_pw == 0)
        ui->le_password->insert("M");
}

void MainWindow::on_kb_n_clicked()
{
    if(usr_or_pw == 1)
        ui->le_username->insert("N");
    else if(usr_or_pw == 0)
        ui->le_password->insert("N");
}

void MainWindow::on_kb_del_clicked()
{
    if(usr_or_pw == 1)
        ui->le_username->backspace();
    else if(usr_or_pw == 0)
        ui->le_password->backspace();
}

void MainWindow::client_disconnected()
{
    serverConnected = false;
}
